/*
 * Copyright (C) 2016 mzlion(and.mz.yq@gmail.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mzlion.easyokhttp.request;

import com.mzlion.core.lang.Assert;
import com.mzlion.core.lang.CollectionUtils;
import com.mzlion.easyokhttp.request.param.UploadFileWrapper;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;

import java.io.File;
import java.io.InputStream;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * 实现带有文件上传功能的表单提交。
 * </p>
 *
 * @author mzlion
 */
public class FormDataPostRequest extends AbstractHttpRequest<FormDataPostRequest> {

    /**
     * 表单提交的参数对列表
     */
    private Map<String, String> formParameters;
    private Map<String, UploadFileWrapper> fileParameters;

    /**
     * 默认构造器
     *
     * @param url 请求地址
     */
    public FormDataPostRequest(String url) {
        super(url);
        this.formParameters = new IdentityHashMap<>();
        this.fileParameters = new ConcurrentHashMap<>();
    }

    /**
     * 设置提交的请求参数及其值
     *
     * @param name  参数名
     * @param value 参数值
     * @return {@linkplain FormDataPostRequest}
     */
    public FormDataPostRequest formParam(String name, String value) {
        Assert.hasLength(name, "Name must not be null.");
        Assert.hasLength(value, "Value must not be null.");
        this.formParameters.put(name, value);
        return this;
    }

    /**
     * 设置提交的请求参数及其值
     *
     * @param parameters 键值对列表
     * @return {@linkplain FormDataPostRequest}
     */
    public FormDataPostRequest formParam(Map<String, String> parameters) {
        Assert.notEmpty(parameters, "Parameters must not be null.");
        for (String name : parameters.keySet()) {
            this.formParameters.put(name, parameters.get(name));
        }
        return this;
    }

    /**
     * 设置提交的文件
     *
     * @param name       参数名
     * @param uploadFile 上传的文件
     * @return {@linkplain FormDataPostRequest}
     */
    public FormDataPostRequest formParam(String name, File uploadFile) {
        Assert.hasLength(name, "Name must not be null.");
        Assert.notNull(uploadFile, "Upload file must not be null.");
        this.fileParameters.put(name, new UploadFileWrapper.Builder().file(uploadFile).build());
        return this;
    }

    /**
     * 设置提交的文件
     *
     * @param name            参数名
     * @param inputStream     上传数据流
     * @param inputStreamName 数据流的标识
     * @return {@linkplain FormDataPostRequest}
     */
    public FormDataPostRequest formParam(String name, InputStream inputStream, String inputStreamName) {
        Assert.hasLength(name, "Name must not be null.");
        Assert.hasLength(inputStreamName, "Filename must not be null.");
        Assert.notNull(inputStream, "InputStream must not be null.");

        UploadFileWrapper uploadFileWrapper = new UploadFileWrapper.Builder().filename(inputStreamName)
                .stream(inputStream).build();
        this.fileParameters.put(name, uploadFileWrapper);
        return this;
    }

    /**
     * 设置提交的文件
     *
     * @param name       参数名
     * @param uploadFile 上传的文件
     * @param mediaType  媒体类型
     * @return {@linkplain FormDataPostRequest}
     */
    public FormDataPostRequest formParam(String name, File uploadFile, MediaType mediaType) {
        Assert.hasLength(name, "Name must not be null.");
        Assert.notNull(uploadFile, "Upload file must not be null.");
        Assert.notNull(mediaType, "MediaType must not be null.");
        this.fileParameters.put(name, new UploadFileWrapper.Builder().file(uploadFile).mediaType(mediaType).build());
        return this;
    }

    /**
     * 获取{@linkplain RequestBody}对象
     */
    @Override
    protected RequestBody generateRequestBody() {
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        if (CollectionUtils.isNotEmpty(this.formParameters)) {
            for (Map.Entry<String, String> entry : this.formParameters.entrySet()) {
                builder.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }
        if (CollectionUtils.isNotEmpty(fileParameters)) {
            UploadFileWrapper uploadFileWrapper;
            for (String name : fileParameters.keySet()) {
                uploadFileWrapper = fileParameters.get(name);
                if (uploadFileWrapper.getFile() != null) {
                    builder.addFormDataPart(name, uploadFileWrapper.getFilename(),
                            RequestBody.create(uploadFileWrapper.getMediaType(), uploadFileWrapper.getFile()));
                } else {
                    builder.addFormDataPart(name, uploadFileWrapper.getFilename(),
                            RequestBody.create(uploadFileWrapper.getMediaType(), uploadFileWrapper.getContent()));
                }
            }
        }
        return builder.build();
    }

    /**
     * 根据不同的请求方式，将RequestBody转换成Request对象
     *
     * @param requestBody 请求体
     * @return {@link Request}
     * @see RequestBody
     */
    @Override
    protected Request generateRequest(RequestBody requestBody) {
        Request.Builder builder = new Request.Builder();
        builder.headers(super.buildHeaders());
        return builder.url(this.buildUrl()).post(requestBody).build();
    }
}
